pub const CHUNK_FIXED:libc::c_int = 0;
pub const CHUNK_RABIN:libc::c_int = 1;
pub const CHUNK_NORMALIZED_RABIN:libc::c_int = 2;
pub const CHUNK_FASTCDC:libc::c_int = 4;
use std::fmt::Debug;

use crate::{chunkAlg_init,fastcdc_init};

#[repr(C)]
pub struct Config {
    chunk_max_size:libc::c_int,
    chunk_min_size:libc::c_int,
    chunk_avg_size:libc::c_int,
    super_feature_subregion_num:libc::c_int,
    features_per_sf:libc::c_int,
    enable_sort_features:libc::c_int,
    chunk_algorithm:libc::c_int,
}

impl Config {
    pub fn config_chunk_min_size(&mut self,chunk_min_size:usize) -> &mut Self{
        self.chunk_min_size = chunk_min_size as libc::c_int;
        self
    }

    pub fn config_chunk_max_size(&mut self,chunk_max_size:usize) -> &mut Self{
        self.chunk_max_size = chunk_max_size as libc::c_int;
        self
    }
    
    pub fn config_chunk_avg_size(&mut self,chunk_avg_size:usize) -> &mut Self{
        self.chunk_avg_size = chunk_avg_size as libc::c_int;
        self
    }
    
    pub fn config_super_feature_subregion_num(&mut self,super_feature_subregion_num:usize) -> &mut Self{
        self.super_feature_subregion_num = super_feature_subregion_num as libc::c_int;
        self
    }

    pub fn config_features_per_sf(&mut self,features_per_sf:usize) -> &mut Self{
        self.features_per_sf = features_per_sf as libc::c_int;
        self
    }
    
    pub fn config_enable_sort_features(&mut self,enable_sort_features:bool) -> &mut Self{
        if enable_sort_features {
            self.enable_sort_features = 1;
        } else {
            self.enable_sort_features = 0;
        }
        self
    }
    
    pub fn config_chunk_algorithm(&mut self,chunk_algorithm:&str) -> &mut Self{
        if chunk_algorithm == "rabin" {
            self.chunk_algorithm = CHUNK_RABIN;
        } else if chunk_algorithm == "fastcdc" {
            self.chunk_algorithm = CHUNK_FASTCDC;
        } else if chunk_algorithm == "fixed" {
            self.chunk_algorithm = CHUNK_FIXED;
        } else {
            panic!("invalid chunk algorithm config {}",chunk_algorithm);
        }
        self
    }

    pub fn chunk_max_size(&self) -> usize {
        self.chunk_max_size as usize
    }

    pub fn chunk_min_size(&self) -> usize {
        self.chunk_min_size as usize
    }
    
    pub fn chunk_avg_size(&self) -> usize {
        self.chunk_avg_size as usize
    }

    pub fn super_feature_subregion_num(&self) -> usize {
        self.super_feature_subregion_num as usize
    }

    pub fn feature_per_sf(&self) -> usize {
        self.features_per_sf as usize
    }

    pub fn enable_sort_features(&self) -> bool {
        if self.enable_sort_features != 0 {
            true
        } else {
            false
        }
    }

    pub fn chunk_algorithm(&self) -> String {
        match self.chunk_algorithm {
            CHUNK_FIXED => "fixed".to_string(),
            CHUNK_RABIN => "rabin".to_string(),
            CHUNK_FASTCDC => "fastcdc".to_string(),
            _=> panic!("invalid chunk algorithm"),
        }
    }

    // features_per_sf:libc::c_int,
    // enable_sort_features:libc::c_int,
    // chunk_algorithm:libc::c_int,

    pub fn chunk_algorithm_init(&mut self) {
        unsafe {
            if self.chunk_algorithm == CHUNK_RABIN {
                let mut pwr:libc::c_int = 0;
                while self.chunk_avg_size != 0 {
                    self.chunk_avg_size >>= 1;
                    pwr += 1;
                }
                self.chunk_avg_size = 1 << (pwr - 1);
    
                assert!(self.chunk_avg_size >= self.chunk_min_size);
                assert!(self.chunk_avg_size <= self.chunk_max_size);
    
                chunkAlg_init();
                //chunking = rabin_chunk_data;
            } else if self.chunk_algorithm == CHUNK_FASTCDC {
                assert!(self.chunk_avg_size <= self.chunk_max_size);
                //chunking = fastcdc_chunk_data;
                chunkAlg_init();
                fastcdc_init(self.chunk_avg_size as u32);
            } else if self.chunk_algorithm == CHUNK_FIXED {
                chunkAlg_init();
            }
        }
    
    }

}

impl Debug for Config {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let enable_sort_features = if self.enable_sort_features != 0 {
            "yes"
        } else {
            "no"
        }.to_string();
        let chunk_algorithm = if self.chunk_algorithm == CHUNK_RABIN {
            "rabin"
        } else if self.chunk_algorithm == CHUNK_FASTCDC {
            "fastcdc"
        } else if self.chunk_algorithm == CHUNK_FIXED {
            "fixed"
        } else {
            panic!("invalid chunk algorithm fmt");
        }.to_string();
        f.debug_struct("Config")
            .field("chunk_algorithm", &chunk_algorithm)
            .field("chunk_min_size", &self.chunk_min_size)
            .field("chunk_max_size", &self.chunk_max_size)
            .field("chunk_avg_size", &self.chunk_avg_size)
            .field("feature_per_sf",&self.features_per_sf)
            .field("super_feature_subregion_num", &self.super_feature_subregion_num)
            .field("enable_sort_features",&enable_sort_features)
            .finish()
    }
}


